package com.cocolover2.andbase.http.api;

import android.support.annotation.NonNull;

import com.cocolover2.andbase.http.OnHttpListener;
import com.cocolover2.andbase.http.request.ProgressRequestBody;

import java.io.File;
import java.io.IOException;
import java.util.Map;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

/**
 * 文件上传帮助类
 * Created by cocolove2 on 17/8/18.
 */

final class OkUploadFiles {
    private static final MediaType MEDIA_TYPE_STREAM = MediaType.parse("application/octet-stream");

    /**
     * 构建文件上传表单(支持多文件和单文件)
     *
     * @param url      上传地址
     * @param params   参数列表
     * @param listener 回调监听
     * @return 返回构建的 request
     */
    private static Request buildUploadFileRequest(String url, @NonNull Map<String, Object> params, final OnHttpListener listener) {
        //配置参数
        MultipartBody.Builder multipartBodyBuilder = new MultipartBody.Builder().setType(MultipartBody.FORM);
        for (Map.Entry<String, Object> entry : params.entrySet()) {
            Object value = entry.getValue();
            String key = entry.getKey();
            if (value instanceof File[]) {//文件数组，多文件
                File[] files = (File[]) value;
                for (File file : files) {
                    RequestBody body = RequestBody.create(MEDIA_TYPE_STREAM, file);
                    multipartBodyBuilder.addFormDataPart(key, file.getName(), body);
                }
            } else if (value instanceof File) {//单文件
                RequestBody body = RequestBody.create(MEDIA_TYPE_STREAM, (File) value);
                multipartBodyBuilder.addFormDataPart(key, ((File) value).getName(), body);
            } else {//其他参数
                multipartBodyBuilder.addFormDataPart(key, value.toString());
            }
        }
        //更新进度
        ProgressRequestBody progressRequestBody = new ProgressRequestBody(multipartBodyBuilder.build(),
                new ProgressRequestBody.Listener() {
                    @Override
                    public void onRequestProgress(final long bytesWritten, final long contentLength, long networkSpeed) {
                        listener.onUploadProgress(bytesWritten, contentLength, networkSpeed);
                    }
                });
        //请求网络
        return new Request.Builder().url(url).post(progressRequestBody).build();
    }

    /**
     * 同步上传文件(不支持异常重试)
     *
     * @param client   okhttpclient
     * @param url      上传地址
     * @param params   上传参数
     * @param listener 回调监听
     */
    @SuppressWarnings("all")
    public static Call uploadFilesSync(@NonNull OkHttpClient client, String url, Map<String, Object> params, OnHttpListener<String> listener) {
        Call call = client.newCall(buildUploadFileRequest(url, params, listener));
        try {
            Response response = call.execute();
            if (listener != null) {
                if (response.isSuccessful()) {
                    String responseStr = response.body() != null ? (response.body().string()) : "body is null";
                    listener.onSuccess(responseStr);
                } else {
                    listener.onFailure(response.code(), response.message());
                }
            }
        } catch (IOException e) {
            if (!call.isCanceled())
                call.cancel();
            if (listener != null)
                listener.onFailure(e.hashCode(), e.getMessage());
        }
        return call;
    }

    /**
     * 文件上传(异步上传)(不支持异常重试)
     * 回调在子线程中
     *
     * @param client   okhttpclient
     * @param url      上传地址
     * @param params   上传参数
     * @param listener 回调监听
     */
    @SuppressWarnings("all")
    public static Call uploadFiles(@NonNull OkHttpClient client, String url, Map<String, Object> params, final OnHttpListener<String> listener) {
        Call call = client.newCall(buildUploadFileRequest(url, params, listener));
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                if (!call.isCanceled()) {
                    call.cancel();
                }
                if (listener != null) {
                    listener.onFailure(e.hashCode(), e.getMessage());
                }
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                if (!call.isCanceled()) call.cancel();
                if (listener != null) {
                    if (response.isSuccessful()) {
                        String responseStr = response.body() != null ? (response.body().string()) : "body is null";
                        listener.onSuccess(responseStr);
                    } else {
                        listener.onFailure(response.code(), response.message());
                    }
                }
            }
        });

        return call;
    }
}
